﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace NCS.IConnect.Core.WebApi
{
    /// <summary>
    /// This custom <see cref="IFilterProvider"/> provides ordered <see cref="FilterInfo"/>.
    /// </summary>
    public class SortableFilterProvider : IFilterProvider
    {
        /// <summary>
        ///  Returns an enumeration of filters.
        /// </summary>
        /// <param name="configuration">The HTTP configuration.</param>
        /// <param name="actionDescriptor">The action descriptor.</param>
        /// <returns>An enumeration of filters.</returns>
        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
        {
            var filters = new List<FilterInfo>(configuration.Filters);
            filters.AddRange(new ActionDescriptorFilterProvider().GetFilters(configuration, actionDescriptor).ToArray());
            return filters.OrderBy(filterInfo => filterInfo, new FilterInfoComparer()).ToArray();
        }

        private class FilterInfoComparer : IComparer<FilterInfo>
        {
            public int Compare(FilterInfo x, FilterInfo y)
            {
                ISortable sortable1 = x.Instance as ISortable;
                ISortable sortable2 = y.Instance as ISortable;
                if (null == sortable1)
                {
                    sortable1 = new SortableWrapper<IFilter>(x.Instance);
                }

                if (null == sortable2)
                {
                    sortable2 = new SortableWrapper<IFilter>(y.Instance);
                }

                int result = sortable1.Order - sortable2.Order;
                if (0 == result)
                {
                    return x.Scope - y.Scope;
                }

                return result;
            }
        }
    }
}
